package cn.jingyuan.swan.system.config;

import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionManager;
import org.springframework.transaction.interceptor.*;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

@Configuration
public class TransactionConfig {

    /** 事务切点表达式 */
    static final String TX_EXPRESSION = "execution (* cn.jingyuan.swan..service..*.*(..))";

    /** 事务超时时间 ，单位：秒 */
    static final int TX_TIMEOUT = 5;

    @Resource
    TransactionManager transactionManager;

    @Bean
    public TransactionInterceptor txInterceptor() {
        RuleBasedTransactionAttribute supports = new RuleBasedTransactionAttribute();
        supports.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS);
        supports.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
        supports.setTimeout(TX_TIMEOUT);


        // 当前存在事务就使用当前事务，当前不存在事务就创建一个新的事务
        RuleBasedTransactionAttribute required = new RuleBasedTransactionAttribute();
        required.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        required.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
        required.setTimeout(TX_TIMEOUT);


        Map<String, TransactionAttribute> txMap = new HashMap<>();

        // SUPPORTS
        txMap.put("get*", supports);
        txMap.put("load*", supports);
        txMap.put("find*", supports);
        txMap.put("query*", supports);
        txMap.put("list*", supports);
        txMap.put("page*", supports);

        // REQUIRED
        txMap.put("add*", required);
        txMap.put("save*", required);
        txMap.put("delete*", required);
        txMap.put("remove*", required);
        txMap.put("update*", required);
        txMap.put("modify*", required);
        txMap.put("*ForUpdate", required);

        txMap.put("*", required);

        NameMatchTransactionAttributeSource attributeSource = new NameMatchTransactionAttributeSource();
        attributeSource.setNameMap(txMap);

        return new TransactionInterceptor(transactionManager, attributeSource);
    }

    @Bean
    public Advisor pointcutAdvisor() {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression(TX_EXPRESSION);

        return new DefaultPointcutAdvisor(pointcut, txInterceptor());
    }

}
